package com.soyorin.shop.controller;

import com.soyorin.shop.entity.Shop;
import com.soyorin.shop.mapper.ShopMapper;
import com.soyorin.shop.service.ShopService;
import com.soyorin.shop.service.ShopStatisticsService;
import org.springframework.http.ResponseEntity;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

/**
 * 商铺控制器
 * 展示高内聚低耦合特性的实现
 * 
 * @author soyorin
 * @version 1.0
 * @since 2024-01-01
 */
@RestController
@RequestMapping("/shop")
public class ShopController {

    @Autowired
    private ShopService baseService;

    @Autowired
    private ShopStatisticsService statisticsService;

    // 标准接口一: select-one
    @GetMapping("/{id}")
    @ResponseBody
    public ResponseEntity<Shop> selectById(@PathVariable Long id) {
        Shop Shop = baseService.getById(id);
        if(Shop != null) { // return1: 成功查询到数据
            return ResponseEntity.status(200).body(Shop);
        } else { // return2: 未找到对应数据
            return ResponseEntity.status(404).body(null);
        }
    }

    // 标准接口二: select-all
    @GetMapping
    @ResponseBody
    public PageInfo<Shop> selectAll(
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Shop> list = baseService.list();
        return new PageInfo<>(list);
    }

    // 标准接口三: insert
    @PostMapping
    @ResponseBody
    public ResponseEntity<Shop> insert(@RequestBody Shop Shop) {
        boolean result = baseService.save(Shop);
        if(result) { // return1: 成功插入数据
            return ResponseEntity.status(200).body(Shop);
        } else { // return2: 插入数据失败
            return ResponseEntity.status(500).body(null);
        }
    }

    // 标准接口四: delete
    @DeleteMapping("/{id}")
    @ResponseBody
    public ResponseEntity<Shop> delete(@PathVariable Long id) {
        Shop Shop = baseService.getById(id);
        if(Shop != null) {
            boolean result = baseService.removeById(id);
            if(result) { // return1: 成功删除数据
                return ResponseEntity.status(200).body(Shop);
            } else { // return2: 删除数据失败
                return ResponseEntity.status(500).body(Shop);
            }
        } else { // return3: 未找到对应数据
            return ResponseEntity.status(404).body(null);
        }
    }

    // 标准接口五: update
    @PutMapping("/{id}")
    @ResponseBody
    public ResponseEntity<Shop> update(
            @PathVariable Long id,
            @RequestBody Shop Shop) {
        Shop.setId(id);
        boolean result = baseService.updateById(Shop);
        Shop updateShop = baseService.getById(Shop.getId());
        if(result && updateShop != null) { // return1: 成功更新数据
            return ResponseEntity.status(200).body(updateShop);
        } else { // return2: 更新数据失败
            return ResponseEntity.status(500).body(Shop);
        }
    }

    // 标准接口六: select-eq
    @PostMapping("/select-eq")
    @ResponseBody
    public ResponseEntity<List<Shop>> selectEq(
            @RequestBody Map<String,Object> conditions) {
        QueryWrapper<Shop> wrapper = new QueryWrapper<>();
        for(Map.Entry<String, Object> entry : conditions.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            wrapper.eq(key, value);
        }
        List<Shop> list = baseService.list(wrapper);
        if(list != null) { // return1: 成功查询到数据
            return ResponseEntity.status(200).body(list);
        } else { // return2: 未找到对应数据
            return ResponseEntity.status(404).body(null);
        }
    }

    // 高内聚体现：所有商铺查询功能集中在一个控制器中
    @GetMapping("/user-id")
    @ResponseBody
    public String userid(
            @RequestParam Long userId
    ){
        QueryWrapper<Shop> wrapper = new QueryWrapper<>();
        wrapper.eq("rela_user_id", userId);
        List<Shop> list = baseService.list(wrapper);
        return list.toString();
    }

    // 分页查询1:离我最近的优先显示
    @GetMapping("/address-near")
    @ResponseBody
    public PageInfo<Shop> selectAddressNear(
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize,
            @RequestParam double positionX,
            @RequestParam double positionY
    ){
        PageHelper.startPage(pageNum, pageSize);
        List<Shop> list = baseService.selectByDistance(positionX, positionY);
        return new PageInfo<>(list);
    }

    // 分页查询2:给定人均价区间
    @GetMapping("/range")
    @ResponseBody
    public PageInfo<Shop> selectRange(
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize,
            @RequestParam int avAmountMin,
            @RequestParam int avAmountMax){
        PageHelper.startPage(pageNum, pageSize);
        QueryWrapper<Shop> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("av_amount", avAmountMin)
                .lt("av_amount", avAmountMax);
        List<Shop> list = baseService.list(queryWrapper);
        return new PageInfo<>(list);
    }

    // 分页查询:高分优先
    @GetMapping("/av-rating-hign")
    @ResponseBody
    public PageInfo<Shop> selectRange(
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize){
        PageHelper.startPage(pageNum, pageSize);
        List<Shop> list = baseService.selectByRatingDesc();
        return new PageInfo<>(list);
    }

    // 分页查询:店铺名称中带关键字
    @GetMapping("/search")
    @ResponseBody
    public PageInfo<Shop> selectSearch(
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize,
            @RequestParam String keyword){
        PageHelper.startPage(pageNum, pageSize);
        QueryWrapper<Shop> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name", keyword);
        List<Shop> list = baseService.list(queryWrapper);
        return new PageInfo<>(list);
    }

    // ========== 展示高内聚低耦合特性的新接口 ==========

    /**
     * 获取商铺统计信息
     * 高内聚体现：统计功能集中在商铺模块中
     * 低耦合体现：通过ID参数，不直接依赖其他服务
     */
    @GetMapping("/{id}/statistics")
    @ResponseBody
    public ResponseEntity<ShopStatisticsService.ShopStatistics> getShopStatistics(@PathVariable Long id) {
        ShopStatisticsService.ShopStatistics statistics = statisticsService.getShopStatistics(id);
        if (statistics != null) {
            return ResponseEntity.ok(statistics);
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    /**
     * 获取所有商铺统计概览
     * 高内聚体现：统计功能集中在商铺模块中
     * 低耦合体现：不依赖外部服务，自包含的统计逻辑
     */
    @GetMapping("/statistics/overview")
    @ResponseBody
    public ResponseEntity<ShopStatisticsService.ShopStatisticsOverview> getStatisticsOverview() {
        ShopStatisticsService.ShopStatisticsOverview overview = statisticsService.getShopStatisticsOverview();
        return ResponseEntity.ok(overview);
    }

    /**
     * 按评分分组获取商铺统计
     * 高内聚体现：统计功能集中在商铺模块中
     * 低耦合体现：使用内部数据，不依赖外部服务
     */
    @GetMapping("/statistics/rating-groups")
    @ResponseBody
    public ResponseEntity<Map<String, Long>> getShopCountByRating() {
        Map<String, Long> ratingGroups = statisticsService.getShopCountByRating();
        return ResponseEntity.ok(ratingGroups);
    }

    /**
     * 更新商铺月订单量
     * 高内聚体现：商铺数据更新功能集中在商铺模块中
     * 低耦合体现：通过参数传递，不直接依赖订单服务
     */
    @PutMapping("/{id}/monthly-orders")
    @ResponseBody
    public ResponseEntity<String> updateMonthlyOrderCount(
            @PathVariable Long id,
            @RequestParam Integer newOrderCount) {
        try {
            statisticsService.updateMonthlyOrderCount(id, newOrderCount);
            return ResponseEntity.ok("月订单量更新成功");
        } catch (Exception e) {
            return ResponseEntity.badRequest().body("更新失败: " + e.getMessage());
        }
    }

    /**
     * 更新商铺平均评分
     * 高内聚体现：商铺数据更新功能集中在商铺模块中
     * 低耦合体现：通过参数传递，不直接依赖评分服务
     */
    @PutMapping("/{id}/rating")
    @ResponseBody
    public ResponseEntity<String> updateAverageRating(
            @PathVariable Long id,
            @RequestParam Double newRating) {
        try {
            statisticsService.updateAverageRating(id, newRating);
            return ResponseEntity.ok("平均评分更新成功");
        } catch (Exception e) {
            return ResponseEntity.badRequest().body("更新失败: " + e.getMessage());
        }
    }

    /**
     * 检查商铺是否营业
     * 高内聚体现：商铺状态检查功能集中在商铺模块中
     * 低耦合体现：使用内部时间逻辑，不依赖外部服务
     */
    @GetMapping("/{id}/open-status")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> getShopOpenStatus(@PathVariable Long id) {
        Shop shop = baseService.getById(id);
        if (shop == null) {
            return ResponseEntity.notFound().build();
        }

        boolean isOpen = isShopOpen(shop);
        Map<String, Object> status = new HashMap<>();
        status.put("shopId", id);
        status.put("shopName", shop.getName());
        status.put("isOpen", isOpen);
        status.put("startTime", shop.getStartTime());
        status.put("endTime", shop.getEndTime());
        
        return ResponseEntity.ok(status);
    }

    /**
     * 获取商铺配送范围信息
     * 高内聚体现：商铺地理位置功能集中在商铺模块中
     * 低耦合体现：使用内部计算逻辑，不依赖地图服务
     */
    @GetMapping("/{id}/delivery-info")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> getDeliveryInfo(@PathVariable Long id) {
        Shop shop = baseService.getById(id);
        if (shop == null) {
            return ResponseEntity.notFound().build();
        }

        Map<String, Object> deliveryInfo = new HashMap<>();
        deliveryInfo.put("shopId", id);
        deliveryInfo.put("shopName", shop.getName());
        deliveryInfo.put("positionX", shop.getPositionX());
        deliveryInfo.put("positionY", shop.getPositionY());
        deliveryInfo.put("deliveryFee", shop.getDeliveryFee());
        deliveryInfo.put("minOrderAmount", shop.getMinOrderAmount());
        deliveryInfo.put("address", shop.getAddress());
        
        return ResponseEntity.ok(deliveryInfo);
    }

    /**
     * 检查商铺是否在配送范围内
     * 高内聚体现：商铺地理位置功能集中在商铺模块中
     * 低耦合体现：通过参数传递用户位置，不依赖用户服务
     */
    @GetMapping("/{id}/in-delivery-range")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> checkDeliveryRange(
            @PathVariable Long id,
            @RequestParam double userPositionX,
            @RequestParam double userPositionY,
            @RequestParam(defaultValue = "5.0") double maxDistance) {
        
        Shop shop = baseService.getById(id);
        if (shop == null) {
            return ResponseEntity.notFound().build();
        }

        double distance = calculateDistance(userPositionX, userPositionY, 
                                         shop.getPositionX(), shop.getPositionY());
        boolean inRange = distance <= maxDistance;

        Map<String, Object> result = new HashMap<>();
        result.put("shopId", id);
        result.put("shopName", shop.getName());
        result.put("userPositionX", userPositionX);
        result.put("userPositionY", userPositionY);
        result.put("shopPositionX", shop.getPositionX());
        result.put("shopPositionY", shop.getPositionY());
        result.put("distance", distance);
        result.put("maxDistance", maxDistance);
        result.put("inRange", inRange);
        
        return ResponseEntity.ok(result);
    }

    // ========== 私有辅助方法 ==========

    /**
     * 检查商铺是否营业
     * 高内聚体现：商铺业务逻辑集中在模块内部
     */
    private boolean isShopOpen(Shop shop) {
        if (shop.getStartTime() == null || shop.getEndTime() == null) {
            return false;
        }
        
        java.time.LocalTime now = java.time.LocalTime.now();
        return !now.isBefore(shop.getStartTime()) && !now.isAfter(shop.getEndTime());
    }

    /**
     * 计算两点间距离
     * 高内聚体现：地理位置计算逻辑集中在模块内部
     */
    private double calculateDistance(double x1, double y1, double x2, double y2) {
        return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
    }
}